package com.leyou.search.service;

import com.leyou.common.pojo.PageResult;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.SpecParam;
import com.leyou.search.client.BrandClient;
import com.leyou.search.client.CategoryClient;
import com.leyou.search.client.SpecificationClient;
import com.leyou.search.pojo.Goods;
import com.leyou.search.pojo.SearchRequest;
import com.leyou.search.pojo.SearchResult;
import com.leyou.search.respository.GoodsRepository;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: taft
 * @Date: 2018-10-19 9:12
 */
@Service
public class SearchService {

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private SpecificationClient specificationClient;

    public SearchResult queryGoods(SearchRequest searchRequest) {


        String key = searchRequest.getKey();

        if (StringUtils.isBlank(key)) {
            return null;
        }


        //问题在于，人家可能是分页的，并且需要真正的总页数，总条目数

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();


        //使用请求过滤参数以及其他请求条件来封装一个查询条件
        QueryBuilder query = buildBasicQueryWithFilter(searchRequest);

        queryBuilder.withQuery(query);

        //构造分页条件
        queryBuilder.withPageable(PageRequest.of(searchRequest.getPage(), searchRequest.getSize()));


        //添加聚合条件
        // 1.3、聚合
        String categoryAggName = "category"; // 商品分类聚合名称


        queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));
        String brandAggName = "brand"; // 品牌聚合名称

        queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));

        AggregatedPage<Goods> search = (AggregatedPage<Goods>) this.goodsRepository.search(queryBuilder.build());

        //解析聚合结果

        //返回结果要分类以及品牌的聚合结果，并且要的是汉字，我们拿到的是id

        LongTerms categoryTerms = (LongTerms) search.getAggregation(categoryAggName);

        List<LongTerms.Bucket> categoryBuckets = categoryTerms.getBuckets();


        List<Long> categoryIds = new ArrayList<>();
        for (LongTerms.Bucket categoryBucket : categoryBuckets) {
            Long cid3 = categoryBucket.getKeyAsNumber().longValue();
            categoryIds.add(cid3);
        }

        List<String> names = categoryClient.queryNameByIds(categoryIds);


        List<Category> categories = new ArrayList<>();
        for (int i = 0; i < names.size(); i++) {
            Category category = new Category();
            category.setId(categoryIds.get(i));
            category.setName(names.get(i));
            categories.add(category);
        }


        LongTerms brandTerms = (LongTerms) search.getAggregation(brandAggName);

        List<LongTerms.Bucket> brandTermsBuckets = brandTerms.getBuckets();

        List<Long> brandIds = new ArrayList<>();
        for (LongTerms.Bucket brandTermsBucket : brandTermsBuckets) {
            Long brandId = brandTermsBucket.getKeyAsNumber().longValue();
            brandIds.add(brandId);
        }

        List<Brand> brandList = this.brandClient.queryBrandByIds(brandIds);


        //当前商品所属的分类唯一时才做规格参数的聚合
        List<Map<String, Object>> specs = null;
        if (categories.size()==1){
            specs = getSpecs(categories.get(0).getId(),query);

        }

        return new SearchResult(search.getTotalElements(), new Long(search.getTotalPages()), search.getContent(), categories, brandList, specs);
    }



    //用来封装其他的规格参数的方法
    private List<Map<String,Object>> getSpecs(Long cid,QueryBuilder query){


        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //关于规格参数的聚合应该跟着查询走，比如查的是华为，就不应该聚合小米的数据
        queryBuilder.withQuery(query);


        List<Map<String, Object>> specs = new ArrayList<>();

        List<SpecParam> specParams = this.specificationClient.querySpecParam(null, cid, true, null);

        for (SpecParam specParam : specParams) {
            //根据规格参数的名称进行聚合
            String key  = specParam.getName();
            queryBuilder.addAggregation(AggregationBuilders.terms(key).field("specs."+key+".keyword"));
        }


        AggregatedPage<Goods> search = (AggregatedPage<Goods>) this.goodsRepository.search(queryBuilder.build());

        Map<String, Aggregation> stringAggregationMap = search.getAggregations().asMap();

        for (SpecParam specParam : specParams) {
            String key = specParam.getName();
            StringTerms stringTerms = (StringTerms) stringAggregationMap.get(key);

            List<StringTerms.Bucket> buckets = stringTerms.getBuckets();

            List<String> value = new ArrayList<>();

            for (StringTerms.Bucket bucket : buckets) {
               value.add(bucket.getKeyAsString());
            }
            Map<String,Object> spec = new HashMap<>();
            spec.put("k",key);
            spec.put("options",value);

            specs.add(spec);
        }

        return specs;

    }


    // 构建基本查询条件
    private QueryBuilder buildBasicQueryWithFilter(SearchRequest request) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 基本查询条件
        queryBuilder.must(QueryBuilders.matchQuery("all", request.getKey()).operator(Operator.AND));
        // 过滤条件构建器
        BoolQueryBuilder filterQueryBuilder = QueryBuilders.boolQuery();
        // 整理过滤条件
        Map<String, String> filter = request.getFilter();
        for (Map.Entry<String, String> entry : filter.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            // 商品分类和品牌已经聚合
            if (key != "cid3" && key != "brandId") {
                key = "specs." + key + ".keyword";
            }
            // 字符串类型，进行term查询
            filterQueryBuilder.must(QueryBuilders.termQuery(key, value));
        }
        // 添加过滤条件
        queryBuilder.filter(filterQueryBuilder);
        return queryBuilder;
    }
}
